# coding=utf-8
'''
    author: lm,
    date: 2025-06-08,
    python version: 3.6
'''
import face_recognition
import cv2
import numpy as np
import numpy
import time
import pymysql
import os
import datetime
import threading
import multiprocessing
from paho.mqtt import client as mqtt_client
import requests
import logging
import motro_control




# 配置日志记录
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')

from face_init import known_face_names, known_face_encodings, master_photos, master_face_encoding
# MQTT_Information
broker = 'sc96bd0a.ala.cn-hangzhou.emqxsl.cn'
port = 8883
topic = "/facerecognition"
client_id = f'cameral'
username = 'lm'
password = '12345678'

# 创建数据库游标
db = ''
cursor = ''

# 初始化一些变量
video_capture = ''
face_locations = []
face_encodings = []
face_names = []
process_this_frame = True
upgit_cmd = '/home/zb/UpgitUpload/upgit ./face.jpg'
last_name = "Unknown"
last_write_time = time.time()
write_interval = 3



def init():
    global db, cursor, video_capture
    # 获取摄像头的引用
    video_capture = cv2.VideoCapture(0)
    # 加载图片并学习如何识别
    i = 0
    for master_name in known_face_names:
        photo_path = "master_photos/" + master_name + ".jpg"
        master_photos.append(face_recognition.load_image_file(photo_path))
        master_face_encoding.append(face_recognition.face_encodings(master_photos[i])[0])
        known_face_encodings.append(master_face_encoding[i])
        i += 1
    # connect to database
    try:
        db = pymysql.connect(host='sh-cynosdbmysql-grp-2gf1ewak.sql.tencentcdb.com', user='root', passwd='Aa123321',
                             port=28451, database='project_lm')
        print('database connected!')
        cursor = db.cursor()
    except:
        print('something wrong!')

# def init():
#     global db, cursor, video_capture
#     # 获取摄像头的引用
#     video_capture = cv2.VideoCapture(0)
#     try:
#         i = 0
#         master_photos.clear()
#         master_face_encoding.clear()
#
#         for master_name in known_face_names:
#             photo_path = f"master_photos/{master_name}.jpg"
#             image = face_recognition.load_image_file(photo_path)
#             master_photos.append(image)
#
#             # 提取面部特征
#             encoding = face_recognition.face_encodings(image)
#             if len(encoding) > 0:
#                 master_face_encoding.append(encoding[0])
#                 known_face_encodings.append(encoding[0])
#             else:
#                 print(f"未检测到 {master_name} 的人脸")
#             i += 1
#
#         print("init_face() 执行完成。")
#     except Exception as e:
#         print(f"init_face() 发生异常: {e}")
    # connect to database
    # try:
    #     db = pymysql.connect(host='sh-cynosdbmysql-grp-2gf1ewak.sql.tencentcdb.com', user='root', passwd='Aa123321',
    #                          port=28451, database='project_lm')
    #     print('database connected!')
    #     cursor = db.cursor()
    # except:
    #     print('something wrong!')


# 写入entry_records表
def write_to_database(new_id, image_url, current_datetime):
    # 增加记录语句
    query = "INSERT INTO entry_records (id, image, etime) VALUES (%s, %s, %s)"
    values = (new_id, image_url, current_datetime)

    try:
        cursor.execute(query, values)
        db.commit()
        logging.info(f"Successfully wrote to database with id {new_id}")
    except Exception as e:
        logging.error(f"Failed to write to database: {e}")


# 处理视频帧
def video_processing(frame):
    # 声明全局变量
    global face_locations
    global face_encodings

    # 将视频帧的大小调整为1/4，以加快人脸识别处理速度
    small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)

    # 将图像从BGR颜色（OpenCV使用的）转换为RGB颜色（face_recognition使用的）
    rgb_small_frame = numpy.ascontiguousarray(small_frame[:, :, ::-1])

    # 在当前视频帧中查找所有人脸和人脸编码
    face_locations = face_recognition.face_locations(rgb_small_frame)
    face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)


# 显示结果
def display_face_results(frame):
    # 声明全局变量
    global face_locations
    global face_names

    for (top, right, bottom, left), name in zip(face_locations, face_names):
        # 将脸部位置还原为原始帧的大小
        top *= 4
        right *= 4
        bottom *= 4
        left *= 4

        # 在人脸周围绘制一个框
        cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)

        # 在人脸下方绘制一个带有名字的标签
        cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
        font = cv2.FONT_HERSHEY_DUPLEX
        cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)

    cv2.imshow('Video', frame)


# This function is used to connect to MQTT
def connect_mqtt() -> mqtt_client:
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            logging.info("Connected to MQTT Broker!")
        else:
            logging.error(f"Failed to connect, return code {rc}\n")

    # Set Connecting Client ID
    client = mqtt_client.Client(client_id)
    # Set CA certificate
    client.tls_set(ca_certs='./emqxsl-ca.crt')
    client.username_pw_set(username, password)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client


def subscribe(client: mqtt_client):
    def on_message(client, userdata, msg):
        logging.info(f"Received `{msg.payload}` from `{msg.topic}` topic")

        # 使用线程异步处理耗时操作
        threading.Thread(target=handle_mqtt_message, args=(msg,)).start()

    client.subscribe(topic)
    client.on_message = on_message


def handle_mqtt_message(msg):
    try:
        mqtt_order = msg.payload.split(b',')
        if mqtt_order[0] == b'photo':
            image_url = mqtt_order[1].decode('utf-8')
            name = mqtt_order[2].decode('utf-8')
            r = requests.get(image_url)
            setJpgName = f"master_photos/{name}.jpg"
            with open(setJpgName, "wb") as f:
                f.write(r.content)
            logging.info(f"Saved photo to {setJpgName}")
    except Exception as e:
        logging.error(f"Error handling MQTT message: {e}")



def openByface():
    init()
    global process_this_frame, face_names, last_name, last_write_time, write_interval, last_motor_activation_time, motor_activation_interval
    while True:
        ret, frame = video_capture.read()
        if process_this_frame:
            video_processing(frame)
            face_names = []

            for face_encoding in face_encodings:
                matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
                name = "Unknown"
                face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
                best_match_index = np.argmin(face_distances)

                if matches[best_match_index]:
                    name = known_face_names[best_match_index]

                    current_time = time.time()
                    if current_time - last_write_time >= write_interval:
                        if name != "Unknown":
                            try:
                                motro_control.send_motor_on_command()  # 调用电机控制函数
                                logging.info(f"Motor turned ON for user: {name}")
                            except Exception as e:
                                logging.error(f"Failed to turn on motor: {e}")
                        cv2.imwrite('./face.jpg', frame)
                        image_url = os.popen(upgit_cmd).readlines()
                        current_datetime = datetime.datetime.now()
                        new_id = int(current_datetime.strftime("%m%d%H%M%S"))
                        current_datetime = current_datetime.strftime("%Y-%m-%d %H:%M:%S")
                        write_to_database(new_id, image_url, current_datetime)
                        last_write_time = current_time
                        last_name = name
                face_names.append(name)
        process_this_frame = not process_this_frame
        display_face_results(frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    video_capture.release()
    cv2.destroyAllWindows()



def openByid():
    client = connect_mqtt()
    subscribe(client)
    client.loop_forever()


if __name__ == "__main__":
    byFace_thread = threading.Thread(target=openByface)
    byId_thread = threading.Thread(target=openByid)
    byFace_thread.start()
    byId_thread.start()



